//入场动画
import { ExpandIframeCommand, ShowcaseStartCommand, ShowcaseStopCommand, StartApplicationCommand } from "../command/showcase.command"
import keyConst from "../constant/key.const"
import LangKey from "../constant/lang.key"
import ModelData from "../data/ModelData"
import SettingsData from "../data/SettingsData"
import EngineContext from "../EngineContext"
import { phaseMin } from "../enum/phase.enum"
import { AppPhaseChangeMessage } from "../message/app.message"
import { ModelLoadProgressMessage } from "../message/model.message"
import { ShowcaseExpansionMessage } from "../message/showcase.message"
import browserUtil from "../utils/browser.util"
import funcUtil from "../utils/func.util"
import Logger from "../utils/Logger"
import OpenDeferred from "../utils/OpenDeferred"
import LocaleModule from "./LocaleModule"
import { Model } from "./ModelDataModule"
import Module from "./Module"

class ProgressRadial {
  lastProgress: number
  currentProgress: number
  webpackChunks: any[]
  meshAlloc: { alloc: number; loaded: number }
  showingProgress: boolean
  progressElm: HTMLElement
  engine: any
  meshProgressBinding: any
  constructor(e) {
    this.lastProgress = 0
    this.currentProgress = 0
    this.webpackChunks = []
    this.meshAlloc = { alloc: 2000000, loaded: 0 }
    this.showingProgress = !1
    this.progressElm = document.getElementById("bar")
    window.addEventListener("WebpackChunkProgress", this.onWebpackChunkProgress.bind(this))
    this.engine = e
    this.meshProgressBinding = this.onMeshLoadProgress.bind(this)
    this.engine.subscribe(ModelLoadProgressMessage, this.meshProgressBinding)
  }
  showProgress() {
    this.showingProgress = !0
    this.setProgress(this.currentProgress)
  }
  setDone() {
    this.currentProgress = 100
    this.setProgress(this.currentProgress)
    this.engine.unsubscribe(ModelLoadProgressMessage, this.meshProgressBinding)
  }
  setProgress(e) {
    if (!this.progressElm || isNaN(e)) return
    this.lastProgress = Math.max(this.lastProgress, e)
    e = this.lastProgress
    const t = Number.parseFloat(this.progressElm.getAttribute("r") || "0"),
      i = Math.PI * (2 * t),
      n = ((100 - (e = Math.max(Math.min(e, 100), 0))) / 100) * i
    this.progressElm.style.strokeDashoffset = n.toString(10)
  }
  calcProgress() {
    let e = 0,
      t = 0
    this.webpackChunks.forEach(i => {
      e += i.loaded
      t += i.total
    })
    e += this.meshAlloc.loaded
    t += this.meshAlloc.alloc
    this.currentProgress = 75 * Math.min(e / t, 1)
    this.showingProgress && this.setProgress(this.currentProgress)
  }
  onWebpackChunkProgress(e) {
    this.webpackChunks[e.chunkID]
      ? (this.webpackChunks[e.chunkID].loaded = e.loaded)
      : (this.webpackChunks[e.chunkID] = {
          loaded: e.loaded,
          total: e.total
        })
    this.calcProgress()
  }
  onMeshLoadProgress(e) {
    this.meshAlloc.loaded = (e.loaded / e.total) * this.meshAlloc.alloc
    this.calcProgress()
  }
}

const E = new Logger("loading-gui")
export default class LoadingGui extends Module {
  playPromise: OpenDeferred<any>
  resolvePlayPromise: (e: any, t: any) => Promise<any>
  config: any
  settings: SettingsData
  playIcon: HTMLElement
  progressUI: ProgressRadial
  engine: EngineContext
  onAppPhaseChangeMessage: (e: any) => Promise<void>
  uiRoot: HTMLElement
  locale: LocaleModule
  model: Model["details"]
  presentedBy: HTMLElement
  poweredBy: HTMLElement
  mpLogo: HTMLImageElement
  circleLoader: HTMLElement
  nameHeader: HTMLElement
  background: HTMLElement
  tint: HTMLElement
  constructor() {
    super(...arguments)
    this.name = "loading-ui"
    this.playPromise = new OpenDeferred()
    this.resolvePlayPromise = async (e, t) => {
      if (this.config.allowPlayInIframe || !this.config.startNewTab) {
        if (browserUtil.diffWindow())
          if (t && (this.config.allowPlayInIframe || 1 === funcUtil.getUrlParams("expand", 0))) this.toggleIframeExpansion(!0)
          else if (!this.config.allowPlayInIframe) {
            const e: any = browserUtil.queryToMap()
            t && (e.edit = "1"), (e.back = "1"), delete e.cloudEdit
            const i = Object.keys(e)
                .map(t => t + "=" + e[t])
                .join("&"),
              n = `${window.location.origin}${window.location.pathname}?${i}`
            try {
              return void (window.top.location.href = n)
            } catch (e) {
              E.debug("Couldn't set top window location; was Showcase sandboxed?"), E.debug(e)
            }
          }
        t && this.settings.setProperty("quickstart", !0)
        e && (this.config.noUi || (this.playIcon.classList.add("hidden"), this.progressUI.showProgress()), this.playPromise.resolve())
      }
    }
    this.toggleIframeExpansion = e => {
      const t = e ? new ShowcaseStartCommand() : new ShowcaseStopCommand()
      this.engine.commandBinder.issueCommand(t), this.engine.broadcast(new ShowcaseExpansionMessage(e))
    }
    this.onAppPhaseChangeMessage = async e => {
      ;(e.phase !== phaseMin.STARTING && e.phase !== phaseMin.PLAYING && e.phase !== phaseMin.ERROR) ||
        (this.progressUI.setDone(),
        this.config.quickstart ? this.showQuickstartUI() : this.uiRoot.classList.add("faded-out"),
        this.engine.unsubscribe(AppPhaseChangeMessage, this.onAppPhaseChangeMessage))
    }
  }
  toggleIframeExpansion: any
  async init(e, t: EngineContext) {
    this.engine = t
    this.config = e
    this.locale = await t.getModule(LocaleModule)
    this.settings = await t.market.waitForData(SettingsData)
    const i = await t.market.waitForData(ModelData)
    this.model = i.model.details
    this.bindings.push(
      t.commandBinder.addBinding(StartApplicationCommand, async e => {
        this.resolvePlayPromise(e.startup, !0)
      }),
      t.commandBinder.addBinding(ExpandIframeCommand, async e => {
        this.toggleIframeExpansion(e.expand)
      })
    )
    if (!e.noUi) {
      this.bindings.push(
        this.settings.onPropertyChanged(keyConst.title, () => this.renderTitle()),
        this.settings.onPropertyChanged(keyConst.brandingEnabled, () => this.renderBranding()),
        this.settings.onPropertyChanged(keyConst.mlsMode, () => this.renderBranding()),
        t.subscribe(AppPhaseChangeMessage, this.onAppPhaseChangeMessage)
      )
      this.progressUI = new ProgressRadial(t)
      this.loadUi()
      this.getLoadingElements()
      this.renderSplashScreen()
    }
  }
  get waitForPlaying() {
    return this.playPromise.nativePromise()
  }
  loadUi() {
    this.uiRoot = document.getElementById("loading-gui")
    if (!this.uiRoot) throw Error("Loading GUI root not found")
    this.uiRoot.classList.remove("hidden")
    this.config.quickstart && (this.uiRoot.style.pointerEvents = "none")
  }
  getPresentationOptions() {
    const { hideTitle: e, hideBranding: t, quickstart: i } = this.config,
      n = !i && (void 0 !== e ? !e : this.settings.tryGetProperty(keyConst.title, !0)),
      s = this.settings.tryGetProperty(keyConst.mlsMode, !1),
      r = this.settings.tryGetProperty(keyConst.brandingEnabled, !0)
    return { title: n, presentedBy: void 0 !== t ? !t : r && !s }
  }
  getLoadingElements() {
    this.presentedBy = document.getElementById("loading-presented-by")
    this.poweredBy = document.getElementById("loading-powered-by")
    this.mpLogo = document.getElementById("loading-mp-logo") as HTMLImageElement
    this.mpLogo.src = "./images/matterport-logo-light.svg"
    this.mpLogo.alt = this.locale.t(LangKey.ALT_MATTERPORT_LOGO)
    this.circleLoader = document.getElementById("circleLoader")
    this.nameHeader = document.getElementById("loading-header")
    this.background = document.getElementById("loading-background")
    this.tint = document.getElementById("tint")
    this.playIcon = document.getElementById("showcase-play")
  }
  addCobrand() {
    var e
    if (null === (e = this.model) || void 0 === e ? void 0 : e.presentedBy) {
      const e = this.presentedBy.querySelector(".loading-label")
      e && (e.textContent = this.locale.t(LangKey.PRESENTED_BY_CAPS))
      const t = this.presentedBy.querySelector(".subheader")
      t && (t.textContent = this.model.presentedBy), this.presentedBy.classList.remove("hidden")
    }
  }
  hidePlayButtonUI() {
    this.background.style.backgroundImage = "none"
    this.presentedBy.style.transition = "none"
    this.presentedBy.classList.remove("faded-in")
    this.poweredBy.style.transition = "none"
    this.poweredBy.classList.remove("faded-in")
    this.nameHeader.classList.add("hidden")
    this.tint.classList.add("hidden")
    this.circleLoader.classList.add("hidden")
    this.uiRoot.classList.add("quickstart")
  }
  async showQuickstartUI() {
    this.background.classList.add("faded-out")
    await funcUtil.waitRun(500)
    this.presentedBy.style.transition = ""
    this.presentedBy.classList.add("faded-in")
    this.poweredBy.style.transition = ""
    this.poweredBy.classList.add("faded-in")
    await funcUtil.waitRun(2500)
    this.presentedBy.classList.remove("faded-in")
    this.poweredBy.classList.remove("faded-in")
    this.uiRoot.classList.add("faded-out")
  }
  showLoadingUI(e) {
    const t = document.createAttribute("data-status")
    t.value = this.locale.t(LangKey.LOADING)
    const i = document.getElementById("loader-cont")
    i.attributes.setNamedItem(t)
    i.classList.add(this.locale.languageCode)
    i.classList.add("loading")
    e.classList.add("faded-out")
    this.presentedBy.classList.add("faded-in")
  }
  renderTitle() {
    const { title: e } = this.getPresentationOptions()
    this.nameHeader.classList.toggle("hidden", !e)
  }
  renderBranding() {
    const { presentedBy: e } = this.getPresentationOptions()
    e ? this.addCobrand() : this.presentedBy.classList.add("hidden")
  }
  renderSplashScreen() {
    this.renderTitle()
    this.renderBranding()
    this.config.hidePoweredBy && this.poweredBy.classList.add("hidden")
    this.nameHeader.textContent = this.model.name
    this.poweredBy.classList.add("faded-in")
    this.tint.classList.add("faded-in")
    const e = document.getElementById("play-prompt")
    this.playPromise.then(() => {
      this.config.quickstart ? this.hidePlayButtonUI() : this.showLoadingUI(e)
    })
    this.config.autoplay
      ? (this.progressUI.showProgress(), this.playPromise.resolve())
      : (e.classList.remove("hidden"),
        (e.innerText = this.locale.t(LangKey.EXPLORE_3D_SPACE)),
        this.playIcon.classList.remove("hidden"),
        this.uiRoot.addEventListener("click", () => this.resolvePlayPromise(!0, !1)))
    this.renderBackground()
    this.config.allowPlayInIframe || window.scrollTo(0, 0)
  }
  renderBackground() {
    //彭蔚
    // const e = window.devicePixelRatio || 1,
    //   t = Math.max(window.innerWidth, 400)
    // this.background.style.backgroundImage = `url(${this.config.baseUrl}/api/v1/player/models/${this.config.modelId}/thumb?width=${t}&dpr=${e}&disable=upscale)`
  }
}
